/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package luft27.comm.dozor;

import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.Arrays;
import luft27.comm.SerialStream;

/**
 *
 * @author amalikov
 */
public class Protocol {
	public Protocol(SerialStream port) {
		this.port = port;
	}
	
	public void send(Packet p) throws IOException {
		int size = p.data.length + 4;
		byte[] buf = new byte[size];
		ByteBuffer bb = ByteBuffer.wrap(buf).order(ByteOrder.LITTLE_ENDIAN);
		
		bb.put(p.addr);
		bb.put(p.id);
		bb.put((byte)size);
		bb.put(p.data);
		bb.put(crc8(buf, size - 1));
		
		port.write(buf, 0, size);
	}
	
	public Packet receive() throws IOException {
		byte[] buf = new byte[256];
		
		int n = port.read(buf, 0, 4);
		int size = ((int)buf[2]) & 0xFF;

		if (n < 4 || size < 4) {
			return null;
		}

		if (size > 4) {
			n = port.read(buf, 4, size - 4);
			
			if ((n < size - 4) || (crc8(buf, size - 1) != buf[size - 1]))
				return null;
		}

		return new Packet(buf[0], buf[1], Arrays.copyOfRange(buf, 3, size - 1));
	}
	
    /**
     * Name  : CRC-8
     * Poly  : 0x31     x^8 + x^5 + x^4 + 1
     * Init  : 0xFF
     * Revert: false
     * XorOut: 0x00
     * Check : 0xF7 ("123456789")
     * MaxLen: 15 байт(127 бит) - обнаружение
     *   одинарных, двойных, тройных и всех нечетных ошибок
     */
    private byte crc8(byte[] data, int len) {
        short crc = 0xFF;

        for (int n = 0; n < len; ++n) {
            crc ^= data[n];

            for (int i = 0; i < 8; ++i) {
                crc <<= 1;
                if ((crc & 0x100) != 0)
                    crc ^= 0x31;
            }
        }

        return (byte) crc;
    }

	
	private SerialStream port;
}
